package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/prometheus/client_golang/prometheus"
)

type Request struct {
	Jsonrpc string                 `json:"jsonrpc"`
	Method  string                 `json:"method"`
	Params  map[string]interface{} `json:"params"`
	ID      int                    `json:"id"`
	Auth    string                 `json:"auth,omitempty"`
}

type Response struct {
	Jsonrpc string                 `json:"jsonrpc"`
	Result  interface{}            `json:"result"`
	Error   map[string]interface{} `json:"error,omitempty"`
	ID      int                    `json:"id"`
}

type ValueResult struct {
	ItemID    string `json:"itemid"`
	HostID    string `json:"hostid"`
	SnmpOID   string `json:"snmp_oid"`
	Name      string `json:"name"`
	Key       string `json:"key_"`
	LastValue string `json:"lastvalue"`
}

func makeRequest(method string, params map[string]interface{}) Request {
	req := Request{
		Jsonrpc: "2.0",
		Method:  method,
		Params:  params,
		ID:      1,
	}
	return req
}

func sendPost(zabbixURL string, token string, reqBody Request) []interface{} {
	apiReqBody, _ := json.Marshal(reqBody)
	req, err := http.NewRequest("POST", zabbixURL, bytes.NewBuffer(apiReqBody))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Content-Type", contentType)
	req.Header.Set("Authorization", "Bearer "+token)
	client := &http.Client{}

	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	var apiResp Response
	json.NewDecoder(resp.Body).Decode(&apiResp)
	if apiResp.Error != nil {
		panic(fmt.Sprintf("failed to api: %+v", apiResp.Error))
	}
	resultArray, ok := apiResp.Result.([]interface{})
	if ok {
		return resultArray
	} else {
		panic("result is not an array")
	}
}

func getHosts(zabbixURL string, token string) []string {
	apiReq := makeRequest("host.get", map[string]interface{}{
		"output": []string{"hostid"},
	})
	resultArray := sendPost(zabbixURL, token, apiReq)
	var hostids []string
	for _, item := range resultArray {
		if host, ok := item.(map[string]interface{}); ok {
			if hostID, ok := host["hostid"].(string); ok {
				hostids = append(hostids, hostID)
			}
		}
	}

	return hostids
}

func getValues(zabbixURL string, token string, hostids []string) []ValueResult {
	apiReq := makeRequest("item.get", map[string]interface{}{
		"output": []string{
			"hostid",
			"itemid",
			"snmp_oid",
			"name",
			"key_",
			"lastvalue"},
		"hostids": hostids,
	})
	resultArray := sendPost(zabbixURL, token, apiReq)
	var finalValues []ValueResult
	for _, item := range resultArray {
		if valueItem, ok := item.(map[string]interface{}); ok {
			vStruct := ValueResult{
				HostID:    valueItem["hostid"].(string),
				ItemID:    valueItem["itemid"].(string),
				SnmpOID:   valueItem["snmp_oid"].(string),
				Name:      valueItem["name"].(string),
				Key:       valueItem["key_"].(string),
				LastValue: valueItem["lastvalue"].(string),
			}
			finalValues = append(finalValues, vStruct)
		}
	}
	return finalValues
}

func fetchAndUpdateMetrics(exporter *ZabbixExporter) {
	// 获取 hostids
	hostids := getHosts(exporter.zabbixURL, exporter.token)

	// 获取 value results
	valueResults := getValues(exporter.zabbixURL, exporter.token, hostids)

	// 更新 metrics
	for _, vr := range valueResults {
		valueResultMetric.With(prometheus.Labels{
			"hostid":   vr.HostID,
			"itemid":   vr.ItemID,
			"name":     vr.Name,
			"key":      vr.Key,
			"snmp_oid": vr.SnmpOID,
		}).Set(float64(len(vr.LastValue))) // 这里只是一个示例，根据实际情况设置值
	}
}
